package com.freecloud.plug.redisson.bloom;

import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import java.text.NumberFormat;
import java.util.*;

/**
 * Redisson使用Redis实现布隆过滤器
 * @Author: maomao
 * @Date: 2020-03-31 22:13
 */
public class BloomDemo {
    private static final int insertions = 10000;
    /**
     * 用于存放所有实际存在的key，可以取出使用
     */
    public static List<String> lists = new ArrayList<String>(insertions);
    /**
     * 用于存放所有实际存在的key，判断key是否存在
     */
    public static Set<String> sets = new HashSet<String>(insertions);

    private static RedissonClient getClient(){
        Config config = new Config();
        config.setCodec(new org.redisson.client.codec.StringCodec());
        //指定使用单节点部署方式
        config.useSingleServer()
                .setAddress("redis://192.168.10.110:30001")
                .setDatabase(2);
        return Redisson.create(config);
    }

    private static RBloomFilter<String> initData(RedissonClient redisson,List<String> lists, Set<String> sets){
        System.out.println("开始初始化数据。。。");
        long start = System.currentTimeMillis();
        RBloomFilter<String> bloomFilter = redisson.getBloomFilter("bf:sample");
        // 初始化布隆过滤器，预计统计元素数量为10000，期望误差率为0.03
        bloomFilter.tryInit(insertions, 0.03);
        String uuid;
        for (int i = 0; i < insertions; i++) {
            uuid = UUID.randomUUID().toString();
            bloomFilter.add(uuid);
            sets.add(uuid);
            lists.add(uuid);
        }
        System.out.println( String.format("初始化%s数据用时：%s 毫秒",insertions,(System.currentTimeMillis() - start)));
        return bloomFilter;
    }

    public static void main(String[] args) {
        RedissonClient redisson = getClient();
        RBloomFilter<String> bloomFilter = initData(redisson,lists, sets);
        System.out.println("初始化数据完成，开始验证");

        int right = 0; // 正确判断的次数
        int wrong = 0; // 错误判断的次数
        int testCount = 100;
        int getIndex = 10;
        int notFind = (testCount - getIndex);

        //测试100个
        for (int i = 0; i < testCount; i++) {
            String data = i % getIndex == 0 ? lists.get(i / getIndex) : UUID.randomUUID().toString();
            if (bloomFilter.contains(data)) {
                if (sets.contains(data)) {
                    // 判断存在实际存在的时候，命中
                    right++;
                    continue;
                }
                // 判断存在却不存在的时候，错误
                wrong++;
            }
        }

        NumberFormat percentFormat = NumberFormat.getPercentInstance();
        percentFormat.setMaximumFractionDigits(2); //最大小数位数
        float percent = (float) wrong / notFind;
        float bingo = (float) (notFind - wrong) / notFind;

        System.out.println(String.format("认为存在的：%s", right));
        System.out.println(String.format("判断%s个实际存在的元素，布隆过滤器认为存在的：%s",getIndex,right));
        System.out.println(String.format("判断%s个实际不存在的元素，误认为存在的：%s ，命中率：%s ，误判率：%s",
                notFind,wrong, percentFormat.format(bingo) , percentFormat.format(percent))
        );

        //最后关闭RedissonClient
        redisson.shutdown();
    }
}
